#include "BrowserDialog.h"
#include "ui_BrowserDialog.h"
#include <QMouseEvent>
#include "CefViewWidget.h"
#include <core/StyleMgr.h>
#include <array>

bool checkInTitle(const Ui::BrowserDialog *ui, const QPoint& p) {
    //return ui->verticalLayout->itemAt(0)->geometry().contains( p );
    return ui->title->geometry().contains( p );
}

BrowserDialog::BrowserDialog(QWidget *parent)
    : QFrame(parent, Qt::Dialog | Qt::WindowStaysOnTopHint)
    , ui(new Ui::BrowserDialog)
{
    ui->setupUi(this);
    setWindowFlags(Qt::FramelessWindowHint);
    recurseSetMouseTracking(true);
    setStyleSheet(QString(
        "BrowserDialog {"
        "  background-color: #%1; "
        "  border-radius: 3px;"
        "  border: 2px solid #%2;"
        "}"
        "BrowserDialog QPushButton {"
        "  border-radius: 0px;"
        "  background-color: #%1;"
        "  padding: 2px;"
        "  outline: none;"
        "  color: black;"
        "}"
        "BrowserDialog QLabel#title {"
        "  color: #%3;"
        "  padding-left: 72px;"
        "}"
        "BrowserDialog QPushButton:hover {"
        "  background-color: rgb(35,66,74);"
        "}BrowserDialog QPushButton:pressed {"
        "  background-color: #%1;"
        "}"
        "BrowserDialog QPushButton#close {"
        "  image: url(./res/close-line.svg);"
        "}"
        "BrowserDialog QPushButton#min {"
        "  image: url(./res/minimize-line.svg);"
        "}"
        "BrowserDialog QPushButton#pin {"
        "  image: url(./res/pin-normal.svg);"
        "  padding: 0px;"
        "}"
        "BrowserDialog QPushButton#pin:checked {"
        "  image: url(./res/pin-checked.svg);"
        "  padding: 0px;"
        "}"
        "BrowserDialog QPushButton#pin::hover {"
        "  background-color: #%1;"
        "}"
        "BrowserDialog QPushButton#resize {"
        "  image: url(./res/checkbox-blank-line.svg);"
        "  padding: 4px;"
        "}"
        "BrowserDialog QPushButton#resize:checked {"
        "  image: url(./res/checkbox-multiple-blank-line.svg);"
        "  padding: 4px;"
        "}"
        "BrowserDialog QPushButton#refresh {"
        "  image: url(./res/loader-4-line.svg);"
        "  padding: 3px;"
                      "}").arg(StyleMgr::instance().color("MenuTitleHover").rgb(), 0, 16)
                      .arg(StyleMgr::instance().color("InnerBorder").rgb(), 0, 16)
                  .arg(StyleMgr::instance().color("ChartH8").rgb(), 0, 16)
        );
}

BrowserDialog::~BrowserDialog()
{
    delete ui;
    if (resizeDragData) {
        delete resizeDragData;
        resizeDragData = nullptr;
    }
}

void BrowserDialog::setContentWidget(CefViewWidget *content)
{
    if (content_ == nullptr) {
        ui->verticalLayout->addWidget(content);
        content->setMouseTracking(this->hasMouseTracking());

        content_ = content;
    }
}

void BrowserDialog::Navigate(const QString &url)
{
    if (content_) {
        content_->navigateToUrl(url);
    }
}

void BrowserDialog::setTitle(const QString &title)
{
    ui->title->setText(title);
}

void BrowserDialog::on_close_clicked()
{
    close();
}

void BrowserDialog::on_resize_clicked(bool checked)
{
    recurseSetMouseTracking(!checked);
    checked ? showMaximized() : showNormal();
}

void BrowserDialog::on_min_clicked()
{
    showMinimized();
}

void BrowserDialog::on_refresh_clicked()
{
    if (content_) {
        content_->browserReload();
    }
}

void BrowserDialog::on_pin_clicked(bool checked)
{
    setWindowFlag(Qt::WindowStaysOnTopHint, checked);
    show();
}

struct ResizeElement {
    QPoint pos;
    Qt::CursorShape cs;
    int max_dis;
    const std::array<int, 4> coefficients;

    std::array<int, 4> calc_offset(const QPoint& from, const QPoint& to) {
        const QPoint& delta = to - from;
        //return {delta.x(), delta.y(), 0, 0};
        return {delta.x() * coefficients[0],
                delta.y() * coefficients[1],
                delta.x() * coefficients[2],
                delta.y() * coefficients[3]};
    }
};



const QVector<ResizeElement> buildVetexList(const QPoint& pos, const QRect& rect) {
    const QVector<ResizeElement> vertex_list{
        {rect.topLeft(), Qt::CursorShape::SizeFDiagCursor, 5, {1,1,0,0}},
        {rect.topRight(), Qt::CursorShape::SizeBDiagCursor, 5, {0,1,1,0}},
        {rect.bottomRight(), Qt::CursorShape::SizeFDiagCursor, 5, {0,0,1,1}},
        {rect.bottomLeft(), Qt::CursorShape::SizeBDiagCursor, 5, {1,0,0,1}},
        {QPoint{rect.left(), pos.y()}, Qt::CursorShape::SizeHorCursor, 3, {1,0,0,0}},
        {QPoint{pos.x(), rect.top()}, Qt::CursorShape::SizeVerCursor, 3, {0,1,0,0}},
        {QPoint{rect.right(), pos.y()}, Qt::CursorShape::SizeHorCursor, 3, {0,0,1,0}},
        {QPoint{pos.x(), rect.bottom()}, Qt::CursorShape::SizeVerCursor, 3, {0,0,0,1}},
    };
    return vertex_list;
}

struct ResizeDragData {
    QPoint from;
    std::array<int, 4> coefficients;
};

bool BrowserDialog::event(QEvent *evt)
{
    if ((evt->type() == QEvent::MouseMove)) {
        if ((windowState() == Qt::WindowMaximized) || (windowState() == Qt::WindowFullScreen)) {
            goto __end;
        }

        QMouseEvent* e = static_cast<QMouseEvent*>(evt);
        const QPoint& pos = e->pos();
        const QRect& rect = this->rect();

        if (e->buttons() & Qt::LeftButton) {
            if (resizeDragData) {
                const QPoint delta = e->globalPos() - resizeDragData->from;
                resizeDragData->from = e->globalPos();
                setGeometry(geometry().adjusted(delta.x() * resizeDragData->coefficients[0],
                                                delta.y() * resizeDragData->coefficients[1],
                                                delta.x() * resizeDragData->coefficients[2],
                                                delta.y() * resizeDragData->coefficients[3]
                                                ));
            }
        } else {
            QVector<ResizeElement> vertex_list = buildVetexList(pos, rect);

            /*if (checkInTitle(ui, pos)) {
                vertex_list.append(
                    {QPoint{pos.x(), ui->title->geometry().center().y()}, Qt::CursorShape::OpenHandCursor, ui->title->height()/2, {1,1,1,1}}
                );
            }*/

            auto iter = std::find_if(vertex_list.begin(), vertex_list.end(), [pos](const ResizeElement& ele){
                const QPoint delta = ele.pos - pos;
                return delta.manhattanLength() < ele.max_dis;
            });
            if (iter != vertex_list.end()) {
                setCursor(iter->cs);
                return true;
            } else {
                unsetCursor();
            }
        }
    } else if (evt->type() == QEvent::MouseButtonPress) {
        if ((windowState() == Qt::WindowMaximized) || (windowState() == Qt::WindowFullScreen)) {
            goto __end;
        }

        QMouseEvent* e = static_cast<QMouseEvent*>(evt);
        if ((e->button() != Qt::LeftButton)) {
            goto __end;
        }

        const QPoint& pos = e->pos();
        const QRect& rect = this->rect();

        QVector<ResizeElement> vertex_list = buildVetexList(pos, rect);
        if (checkInTitle(ui, pos)) {
            vertex_list.append(
                {QPoint{pos.x(), ui->title->geometry().center().y()}, Qt::CursorShape::ClosedHandCursor, ui->title->height()/2, {1,1,1,1}}
                );
        }

        auto iter = std::find_if(vertex_list.begin(), vertex_list.end(), [pos](const ResizeElement& ele){
            const QPoint delta = ele.pos - pos;
            return delta.manhattanLength() < ele.max_dis;
        });
        if (iter != vertex_list.end()) {
            setCursor(iter->cs);
            if (resizeDragData) {
                delete resizeDragData;
            }
            resizeDragData = new ResizeDragData{e->globalPos(), iter->coefficients};
            return true;
        } else {
            unsetCursor();
            if (resizeDragData) {
                delete resizeDragData;
                resizeDragData = nullptr;
                return true;
            }
        }
    } else if (evt->type() == QEvent::MouseButtonRelease) {
        if (resizeDragData) {
            delete resizeDragData;
            resizeDragData = nullptr;
            unsetCursor();
            return true;
        }
    } else if (evt->type() == QEvent::MouseButtonDblClick) {
        QMouseEvent* e = static_cast<QMouseEvent*>(evt);
        const QPoint& pos = e->pos();
        if (checkInTitle(ui, pos)) {
            ui->resize->click();
        }
    }
__end:
    return QFrame::event(evt);
}

void BrowserDialog::recurseSetMouseTracking(bool tracking)
{
    this->setMouseTracking(tracking);
    const auto& child_widgets = findChildren<QWidget*>();
    for (QWidget *c : child_widgets) {
        c->setMouseTracking(tracking);
    }
}
